package cn.wonderland.base.service.impl;

import cn.wonderland.base.cons.EmailRegisterCon;
import cn.wonderland.base.cons.PhoneRegisterCon;
import cn.wonderland.base.dto.EmailCodeDto;
import cn.wonderland.base.dto.EmailRegisterDto;
import cn.wonderland.base.dto.PhoneRegisterDto;
import cn.wonderland.base.dto.SmsCodeDto;
import cn.wonderland.base.service.VerifyCodeService;
import cn.wonderland.base.util.*;
import cn.wonderland.user.domain.Logininfo;
import cn.wonderland.user.domain.User;
import cn.wonderland.user.mapper.LogininfoMapper;
import cn.wonderland.user.mapper.UserMapper;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.lang3.StringUtils;
import org.springframework.beans.BeanUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.data.redis.core.RedisTemplate;
import org.springframework.stereotype.Service;

import java.io.IOException;
import java.util.concurrent.TimeUnit;

@Service
@Slf4j
public class VerifyCodeServiceImpl implements VerifyCodeService {
    @Autowired
    private RedisTemplate redisTemplate;

    @Autowired
    private UserMapper userMapper;

    @Autowired
    private LogininfoMapper logininfoMapper;

    // 获取图形验证码
    @Override
    public String getImageCode(String imageCodeKey) throws IOException {
        // 生成图形验证码
        String imageCode = VerifyCodeUtils.generateVerifyCode(1);
        // 将图形验证码存到redis中
        redisTemplate.opsForValue().set(imageCodeKey,imageCode,3, TimeUnit.MINUTES);

        return VerifyCodeUtils.VerifyCode(80,30,imageCode);
    }

    // 获取手机验证码
    @Override
    public void smsCode(SmsCodeDto dto) {
        if ("binder".equals(dto.getType())){
            // 发送手机验证码
            sendPhoneMsg(PhoneRegisterCon.BINDER_REDIS_KEY,dto);
        } else {
            // 校验图形验证码
            verifyImage(dto);
            // 发送手机验证码
            sendPhoneMsg(PhoneRegisterCon.REDIS_KEY,dto);
        }


    }

    // 手机号注册
    @Override
    public void phoneRegister(PhoneRegisterDto dto) {
        // 1.校验参数
        // 2.验证短信验证码是否过期、是否正确
        String redisSmsCode = (String) redisTemplate.opsForValue().
                get(String.format(PhoneRegisterCon.REDIS_KEY, dto.getPhone()));
        if (StringUtils.isBlank(redisSmsCode) || !dto.getSmsCode().equals(redisSmsCode)){
            throw new BussinessException("短信验证码有误！");
        }
        // 3.验证两次密码是否正确
        if (!dto.getPassword().equals(dto.getPasswordRepeat())){
            throw new BussinessException("两次密码不一致，请重新输入！");
        }
        // 4.校验手机号是否注册过
        User user = userMapper.findByPhone(dto.getPhone());
        if (user != null) {
            throw new BussinessException("账户已存在，请去登录！");
        }
        // 5.保存数据
        user = dto.getUser(); // 转换user对象
        Logininfo logininfo = new Logininfo();
        BeanUtils.copyProperties(user,logininfo); // 转换logininfo对象
        logininfo.setType(1);
        logininfo.setDisable(1);
        // 添加logininfo对象
        logininfoMapper.add(logininfo);
        // 添加user对象
        user.setLogininfoId(logininfo.getId());
        userMapper.add(user);
    }

    // 获取邮箱验证码
    @Override
    public void emailCode(EmailCodeDto dto) {
        verifyImageEmail(dto);
        sendEmailMsg(dto);

    }

    // 邮箱注册
    @Override
    public void emailRegister(EmailRegisterDto dto) {
        // 1.校验参数
        // 2.验证短信验证码是否过期、是否正确
        String redisEmailCode = (String) redisTemplate.opsForValue().
                get(String.format(EmailRegisterCon.REDIS_KEY, dto.getEmail()));
        if (StringUtils.isBlank(redisEmailCode) || !dto.getEmailCode().equals(redisEmailCode)){
            throw new BussinessException("邮箱验证码有误！");
        }
        // 3.验证两次密码是否正确
        if (!dto.getPassword().equals(dto.getPasswordRepeat())){
            throw new BussinessException("两次密码不一致，请重新输入！");
        }
        // 4.校验手机号是否注册过
        User user = userMapper.findByEmail(dto.getEmail());
        if (user != null) {
            throw new BussinessException("账户已存在，请去登录！");
        }
        // 5.保存数据
        user = dto.getUser(); // 转换user对象
        Logininfo logininfo = new Logininfo();
        BeanUtils.copyProperties(user,logininfo); // 转换logininfo对象
        logininfo.setType(1);
        logininfo.setDisable(1);
        // 添加logininfo对象
        logininfoMapper.add(logininfo);
        // 添加user对象
        user.setLogininfoId(logininfo.getId());
        userMapper.add(user);

    }

    private void sendPhoneMsg(String redisKey,SmsCodeDto dto) {
        // 4.两次发送时间是否大于60s
        Long expire = redisTemplate.getExpire(String.format(redisKey, dto.getPhone()));
        if(null != expire && expire > (PhoneRegisterCon.REDIS_TTL - 1 ) * 60) {
            throw new BussinessException("请勿在60s内重复发送短信验证码！");
        }
        // 5.判断输入的验证码有没有超时，超时重置
        String smsCode = (String) redisTemplate.opsForValue().get(String.format(redisKey, dto.getPhone()));
        if (StringUtils.isBlank(smsCode)){
            smsCode = StrUtils.getComplexRandomString(4); // 验证码过期或者不存在就重新生成一个
        }
        log.info("手机验证码是：" + smsCode);
        // 6.图形验证码使用Redis进行存储
        redisTemplate.opsForValue().set(String.format(redisKey, dto.getPhone()),
                smsCode, PhoneRegisterCon.REDIS_TTL, TimeUnit.MINUTES);
        // 7.发送短信
//        SendMsgUtils.SendMsg(dto.getPhone(),smsCode);
    }

    private void verifyImage(SmsCodeDto dto) {
        // 1.校验参数
        // 2.校验图形验证码是否存在、是否正确
        String redisImageCode = (String) redisTemplate.opsForValue().get(dto.getImageCodeKey());
        // StringUtils.isBlank(redisImageCode 验证是否存在
        // dto.getImageCodeValue().equalsIgnoreCase(redisImageCode) 验证是否正确
        if (StringUtils.isBlank(redisImageCode) || !dto.getImageCodeValue().equalsIgnoreCase(redisImageCode)) {
            throw new BussinessException("图形验证码错误！");
        }
        // 3.验证手机号是否已注册，根据手机号查询用户信息
        User user = userMapper.findByPhone(dto.getPhone());
        if (user != null) {
            throw new BussinessException("账户已存在，请去登录！");
        }
        // 删除图形验证码
        redisTemplate.delete(dto.getImageCodeKey());
    }
    private void verifyImageEmail(EmailCodeDto dto) {
        // 1.校验参数
        // 2.校验图形验证码是否存在、是否正确
        String redisImageCode = (String) redisTemplate.opsForValue().get(dto.getImageCodeKey());
        // StringUtils.isBlank(redisImageCode 验证是否存在
        // dto.getImageCodeValue().equalsIgnoreCase(redisImageCode) 验证是否正确
        if (StringUtils.isBlank(redisImageCode) || !dto.getImageCodeValue().equalsIgnoreCase(redisImageCode)) {
            throw new BussinessException("图形验证码错误！");
        }
        // 3.验证手机号是否已注册，根据手机号查询用户信息
        User user = userMapper.findByEmail(dto.getEmail());
        if (user != null) {
            throw new BussinessException("账户已存在，请去登录！");
        }
        // 删除图形验证码
        redisTemplate.delete(dto.getImageCodeKey());
    }

    private void sendEmailMsg(EmailCodeDto dto) {
        // 4.两次发送时间是否大于60s
        Long expire = redisTemplate.getExpire(String.format(EmailRegisterCon.REDIS_KEY, dto.getEmail()));
        if(null != expire && expire > (EmailRegisterCon.REDIS_TTL - 1 ) * 60) {
            throw new BussinessException("请勿在60s内重复发送邮箱验证码！");
        }
        // 5.判断输入的验证码有没有超时，超时重置
        String emailCode = (String) redisTemplate.opsForValue().get(String.format(EmailRegisterCon.REDIS_KEY, dto.getEmail()));
        if (StringUtils.isBlank(emailCode)){
            emailCode = StrUtils.getComplexRandomString(4); // 验证码过期或者不存在就重新生成一个
        }
        log.info("邮箱验证码是：" + emailCode);
        // 6.图形验证码使用Redis进行存储
        redisTemplate.opsForValue().set(String.format(EmailRegisterCon.REDIS_KEY, dto.getEmail()),
                emailCode, EmailRegisterCon.REDIS_TTL, TimeUnit.MINUTES);
        // 7.发送短信
        MailUtils.sendMail(dto.getEmail(),"您的邮箱验证码是：" + emailCode + ",三分钟内有效！",EmailRegisterCon.REDIS_EMAILTITILE);

    }
}

